import * as Cesium from 'cesium/Cesium'
import Utils from './zkcloud.utils'
import viewerMeasureMixin from './Measure'
import TransformPanel from './TransformEditor';
/**
 * 内部实体
 */
let viewer;
/**
 * 视图模式
 * @type {{"3D": Number, "2D": Number}}
 */
var viewMode = {
    view: Cesium.SceneMode.COLUMBUS_VIEW,
    view3D: Cesium.SceneMode.SCENE3D,
}
/**
 * 影像
 * @type {{google: Cesium.UrlTemplateImageryProvider}}
 */
var provider = {
    google: {url: "http://mt1.google.cn/vt/lyrs=s&hl=zh-CN&x={x}&y={y}&z={z}&s=Gali"},
}

/*******************************************************/
function object(o) {
    function F() {
    }

    F.prototype = o;
    return new F();
}

function extents(child, parent) {
    var prototype = object(parent.prototype);
    prototype.constructor = child;
    child.prototype = prototype;
}

/**
 * 获取颜色
 * @param color
 * @returns {Color}
 */
function getColor(color) {
    if (Object.prototype.toString.call(color) === '[object String]') {
        color = Cesium.Color.fromCssColorString(color)
    } else if (color.length == 4) {
        color = Cesium.Color.fromAlpha(Cesium.Color.fromBytes(color[0], color[1], color[2]), color[3]);
    } else {
        color = Cesium.Color.fromBytes(color[0], color[1], color[2]);
    }
    return color;
}

/**
 * 获取坐标
 * @param position
 * @returns {Cartesian3}
 */
function getPosition(position) {
    var h = position.length === 3 ? position[2] : 0;
    return Cesium.Cartesian3.fromDegrees(position[0], position[1], h);
}

/*******************************************************/

/**
 * 原型模式 创建
 * @constructor
 */
function ZK({access_token, mode, map}) {
    if (access_token) {
        Cesium.Ion.defaultAccessToken = access_token;
    }
    mode = mode ? mode : viewMode.view3D;
    var sceneMode = viewMode[mode];
    var conf = {
        // 需要进行可视化的数据源的集合
        animation: false, // 是否显示动画控件
        shouldAnimate: true,
        homeButton: false, // 是否显示Home按钮
        fullscreenButton: false, // 是否显示全屏按钮
        timeline: false, // 是否显示时间线控件
        sceneModePicker: false, // 是否显示投影方式控件
        navigationHelpButton: false, // 是否显示帮助信息控件
        infoBox: false, // 是否显示点击要素之后显示的信息
        requestRenderMode: true, // 启用请求渲染模式
        scene3DOnly: false, // 每个几何实例将只能以3D渲染以节省GPU内存
        sceneMode: sceneMode, // 初始场景模式 1 2D模式 2 2D循环模式 3 3D模式  Cesium.SceneMode
        fullscreenElement: document.body, // 全屏时渲染的HTML元素 暂时没发现用处
        //加载谷歌卫星影像 (在线)
        // imageryProvider: new Cesium.UrlTemplateImageryProvider({url: "http://mt1.google.cn/vt/lyrs=s&hl=zh-CN&x={x}&y={y}&z={z}&s=Gali"}),
        baseLayerPicker: false, // 是否显示图层选择控件
        geocoder: false, // 是否显示地名查找控件
        // imageryProvider: new Cesium.UrlTemplateImageryProvider({url:'http://192.168.100.62:8888/satellite/{z}/{x}/{y}.jpg'}),

    }
    //加载谷歌卫星影像 (在线)
    if (map && map.type === 'google') {
        if (map.url) {
            provider.google.url = map.url;
        }
        conf.imageryProvider = new Cesium.UrlTemplateImageryProvider(provider.google);
    }
    viewer = this.viewer = new Cesium.Viewer('cesiumContainer', conf);
    // 去除版权信息
    this.viewer._cesiumWidget._creditContainer.style.display = 'none'
    // Cesium3DTileset用来实现大范围的模型场景数据的加载应用
    // 三维倾斜模型、人工建模、BIM模型等等，都可以转换成3DTiles
    //鼠标中键滚动缩放
    this.viewer.scene.screenSpaceCameraController.zoomEventTypes = [Cesium.CameraEventType.MIDDLE_DRAG, Cesium.CameraEventType.WHEEL, Cesium.CameraEventType.PINCH];
    //鼠标右键视角
    this.viewer.scene.screenSpaceCameraController.tiltEventTypes = [Cesium.CameraEventType.RIGHT_DRAG, Cesium.CameraEventType.PINCH];

    //工具实例化 viewer
    Utils.viewer = viewer;
};

var zkEvent = {
    click: Cesium.ScreenSpaceEventType.LEFT_CLICK,
    mousemove: Cesium.ScreenSpaceEventType.MOUSE_MOVE,
};
/**
 * zk 事件
 * @param event
 * @param callback
 */
ZK.prototype.on = function (event, callback) {
    var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
    handler.setInputAction(callback, zkEvent[event]);
}


/******************BaseObject************************/
/**
 * 原型模型
 * @constructor
 */
function BaseObject({type, id, name, url, position, coordinates, renderer, complete}) {
    this.type = type;
    this.id = id;
    this.name = name;
    this.url = url;
    this.position = position;
    this.complete = complete;
    this.coordinates = coordinates;
    this.renderer = renderer;
}

// 移动
BaseObject.prototype.translate = function (translate) {
    var mat = this.modelMatrix;
    translate = {x: translate[0], y: translate[1], z: translate[2]};
    Cesium.Matrix4.multiply(mat, Cesium.Matrix4.fromTranslation(translate), mat);
    this.modelMatrix = mat;
}

// 旋转
BaseObject.prototype.rotate = function (rotate) {
    var mat = this.modelMatrix;
    var rotationX = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromRotationX(Cesium.Math.toRadians(rotate[0])));
    var rotationY = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromRotationY(Cesium.Math.toRadians(rotate[1])));
    var rotationZ = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(rotate[2])));

    Cesium.Matrix4.multiply(mat, rotationX, mat);
    Cesium.Matrix4.multiply(mat, rotationY, mat);
    Cesium.Matrix4.multiply(mat, rotationZ, mat);

    this.modelMatrix = mat;
}
// 旋转，z轴方向
BaseObject.prototype.rotateZ = function (rotateZ) {
    var mat = this.modelMatrix;
    var rotateZ = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(rotateZ)));
    Cesium.Matrix4.multiply(mat, rotateZ, mat);
    this.modelMatrix = mat;
}

// 缩放
BaseObject.prototype.scales = function (scale) {
    var mat = this.modelMatrix;
    scale = {x: scale[0], y: scale[1], z: scale[2]};
    Cesium.Matrix4.multiply(mat, Cesium.Matrix4.fromScale(scale), mat);
    this.modelMatrix = mat;
}


BaseObject.prototype.destroy = function () {
    viewer.scene.primitives.remove(this);
}
BaseObject.prototype.destroyAll = function () {

    // viewer.scene.primitives.removeAll();
}
/******************BaseObject************************/

/******************ZKModel************************/
/**
 * 原型模型
 * @constructor
 */
function ZKModel({type, id, name, url, coordinates, renderer}) {
    BaseObject.call(this, {type, id, url, name, coordinates, renderer});
    var m = this.create();
    this.object = m;
    for (var d in m) {
        this[d] = m[d];
    }
}

//继承BaseObject
extents(ZKModel, BaseObject);


ZKModel.prototype.create = function () {
    //坐标
    var position = getPosition(this.coordinates);
    var hpRoll = new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(0), 0, 0);
    var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpRoll);
    var color = Cesium.Color.LIME;
    var cf = {
        // 模型id
        id: this.id,
        name: this.name,
        // 模型位置
        position: position,
        // 模型方向
        orientation: orientation,
        // 模型资源
        model: {
            // 模型路径
            uri: this.url,
            // 模型最小刻度
            minimumPixelSize: 0.001,
//		            // 模型最大刻度
            maximumSize: 128,
            //设置模型最大放大大小
            maximumScale: 200,
            // 模型是否可见
            show: true,
            // 模型轮廓颜色
            silhouetteColor: Cesium.Color.WHITE,
            // 模型颜色  ，这里可以设置颜色的变化
            // color: color,
            scale: 0.005,
            //是否运行模型中的动画效果
            runAnimations: true
        },
    };
    // 添加模型
    var entity = viewer.entities.add(cf);
    return entity;
}

/******************ZKModel************************/

/******************Model************************/
/**
 * 模型
 * @constructor
 */
function Model({type, id, name, url, coordinates, complete}) {
    BaseObject.call(this, {type, id, url, name, coordinates, complete});
    var m = this.create();
    this.object = m;
    for (var d in m) {
        this[d] = m[d];
    }
}

//继承BaseObject
extents(Model, BaseObject);

Model.prototype.create = function () {
    //坐标
    var position = getPosition(this.coordinates);
    // var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);
    // 生成一个函数，该函数从以提供的原点为中心的参考帧到提供的椭圆体的固定参考帧计算4x4变换矩阵。
    var fixedFrame = Cesium.Transforms.localFrameToFixedFrameGenerator('north', 'west');
    var hpRoll = new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(0), 0, 0);
    var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, fixedFrame, position);

    var gltf = Cesium.Model.fromGltf({
        id: this.id,
        name: name,
        url: this.url,
        // 模型矩阵
        modelMatrix: modelMatrix,
        // 模型最小刻度
        minimumPixelSize: 128,
        // 模型标尺
        scale: 0.005,
        // 模型最大刻度
        maximumScale: 1,
        // 仅用于调试。显示模型绘制时的边界球。
        debugShowBoundingVolume: false,
        // 仅用于调试，显示魔仙绘制时的线框
        debugWireframe: false,
        //是否运行模型中的动画效果
        runAnimations: true,
        // 模型是否可见
        show: true,
    });
    // 添加模型
    var entity = viewer.scene.primitives.add(gltf);
    // 物体加载完成后的回调函数
    if (this.complete) {
        entity.readyPromise.then(this.complete);
    }
    return entity;
}

/******************Model************************/

/******************Point************************/
/**
 * 点对象
 * @constructor
 */
function Point({type, id, name, coordinates, renderer}) {
    BaseObject.call(this, {type, id, name, coordinates, renderer});
    var m = this.create();
    this.object = m;
    for (var d in m) {
        this[d] = m[d];
    }
}

//继承BaseObject
extents(Point, BaseObject);

Point.prototype.create = function () {
    //坐标
    var cf = {
        id: this.id,
        name: this.name,
        position: getPosition(this.coordinates),
        point: new Cesium.PointGraphics({
            color: getColor(this.renderer.color),
            pixelSize: this.renderer.size,
            outlineColor: getColor(this.renderer.lineColor),
            outlineWidth: this.renderer.outlineWidth,
            // translucencyByDistance:renderer.lineOpacity,
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
        }),
        label: {
            text: this.renderer.text,
            show: true,
            showBackground: true,
            font: '14px monospace',
            horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
            verticalOrigin: Cesium.VerticalOrigin.TOP,
            pixelOffset: new Cesium.Cartesian2(5, -20),
            disableDepthTestDistance: Number.POSITIVE_INFINITY
        }
    }
    // 添加模型
    var entity = viewer.entities.add(cf);
    return entity;
}
/******************Point************************/

/******************Line************************/
/**
 * 线对象
 * @constructor
 */
function Line({type, id, name, coordinates, renderer}) {
    BaseObject.call(this, {type, id, name, coordinates, renderer});
    var m = this.create();
    this.object = m;
    for (var d in m) {
        this[d] = m[d];
    }
}

//继承BaseObject
extents(Line, BaseObject);

Line.prototype.create = function () {
    var positions = [];
    for (var i = 0; i < this.coordinates.length; i++) {
        positions.push(getPosition(this.coordinates[i]))
    }
    var cf = {
        id: this.id,
        name: this.name,
        polyline: new Cesium.PolylineGraphics({
            positions: positions,
            clampToGround: true,
            width: this.renderer.width,
            material: getColor(this.renderer.color)
        })
    }
    // 添加模型
    var entity = viewer.entities.add(cf);
    return entity;
}
/******************Line************************/

/******************Polygon************************/
/**
 * 面对象
 * @constructor
 */
function Polygon({type, id, name, coordinates, renderer}) {
    BaseObject.call(this, {type, id, name, coordinates, renderer});
    var m = this.create();
    this.object = m;
    for (var d in m) {
        this[d] = m[d];
    }
}

//继承BaseObject
extents(Polygon, BaseObject);

Polygon.prototype.create = function () {
    var positions = [];
    for (var i = 0; i < this.coordinates.length; i++) {

        for (var j = 0; j < this.coordinates[i].length; j++) {
            positions.push(this.coordinates[i][j])
        }
        if (this.coordinates[i].length === 2) {
            positions.push(0);
        }
    }
    var cf = {
        id: this.id,
        name: this.name,
        polygon: new Cesium.PolygonGraphics({
            hierarchy: Cesium.Cartesian3.fromDegreesArrayHeights(positions),
            fill: this.renderer.fill,
            outline: this.renderer.outline,
            outlineColor: this.renderer.outlineColor,
            outlineWidth: this.renderer.outlineWidth,
            perPositionHeight: true,
            extrudedHeight: this.renderer.extrudedHeight,
            material: getColor(this.renderer.color)
        })
    }
    // 添加模型
    var entity = viewer.entities.add(cf);
    return entity;
}

/******************Polygon************************/
/**
 * 模型类型
 * @type {{LINE: string, MODEL: string}}
 */
var MODEL_TYPE = {
    ZKMODEL: 'ZKModel',
    MODEL: 'Model',
    Point: 'Point',
    LINE: 'Line',
    POLYGON: 'Polygon',
};
/**
 * 创建模型
 * 创建物体
 Parameters:
 Name    Type    Description
 type    String
 物体类型
 id    Number | String
 物体 ID，可通过 THING.Utils.generateUUID() 生成唯一标识
 name    String
 物体名称
 url    String
 模型资源地址（Thing）/图片资源地址（Marker）/页面资源地址（WebView）
 position    Array.<Number>
 物体在世界坐标系下的位置
 complete    function
 物体加载完成后的回调函数
 */
ZK.prototype.create = function ({type, id, name, url, position, coordinates, renderer, complete}) {
    var conf = {};
    conf.type = type,
        conf.id = id || Utils.generateUUID(),
        conf.name = name ? name : conf.id,
        conf.url = url;
    if (position) {
        //物体在世界坐标系下的位置
        var h = position.length === 3 ? position[2] : 0;
        conf.position = [position[0], position[1], h];
    }
    conf.coordinates = coordinates,
        conf.renderer = renderer,
        conf.complete = complete;

    var model;
    switch (type) {
        case MODEL_TYPE.ZKMODEL:
            model = new ZKModel(conf);
            break;
        case MODEL_TYPE.MODEL:
            model = new Model(conf);
            break;
        case MODEL_TYPE.Point:
            model = new Point(conf);
            break;
        case MODEL_TYPE.LINE:
            model = new Line(conf);
            break;
        case MODEL_TYPE.POLYGON:
            model = new Polygon(conf);
            break;
    }
    return model;
}
/**
 * 将相机从当前位置飞到新位置。
 * @param position
 * @param complete
 * @param time
 */
ZK.prototype.flyTo = function ({position, complete, time}) {
    //高度
    var h = position.length === 3 ? position[2] : 0;
    var conf = {
        destination: Cesium.Cartesian3.fromDegrees(position[0], position[1], h)
    };
    // 相机飞行回调
    if (complete) {
        conf.complete = complete;
    }
    // 相机飞行持续时间
    if (time) {
        conf.duration = time / 1000;
    }
    //相机飞行
    viewer.camera.flyTo(conf);
}

/***************************** config**************************************/
ZK.TransformPanel = TransformPanel;
ZK.viewerMeasureMixin = viewerMeasureMixin;
ZK.Util = Utils;
export default ZK
